﻿///////////////////////////////////////////////////////////////////////////////
//	Copyright 2013 JASDev International
//
//	Licensed under the Apache License, Version 2.0 (the "License");
//	you may not use this file except in compliance with the License.
//	You may obtain a copy of the License at
//
//		http://www.apache.org/licenses/LICENSE-2.0
//
//	Unless required by applicable law or agreed to in writing, software
//	distributed under the License is distributed on an "AS IS" BASIS,
//	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//	See the License for the specific language governing permissions and
//	limitations under the License.
///////////////////////////////////////////////////////////////////////////////

using System;
using System.Text;
using System.Collections;

namespace JDI.Pusher.Client
{
	/// <summary>
	/// Represents a Pusher Public channel. Serves as the base class for all other channel types.
	/// </summary>
	public class PusherChannel
	{
		#region Constructors and IDisposable

		internal PusherChannel(string channelName, PusherClient pusher)
		{
			this.isDisposed = false;

			this.name = channelName;
			this.channelType = PusherChannelType.Public;
			this.status = PusherChannelState.NotSubscribed;
			this.pusher = pusher;
			this.eventEmitter = new PusherEventEmitter();
		}

		~PusherChannel()
		{
			this.Dispose(false);
		}

		internal void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (this.isDisposed)
				return;

			if (disposing)
			{
				if (this.eventEmitter != null)
					this.eventEmitter.Dispose();
			}

			this.name = null;
			this.pusher = null;
			this.eventEmitter = null;
			this.statusCallback = null;

			// make sure we don't dispose again
			this.isDisposed = true;
		}

		#endregion


		#region Properties

		public string Name
		{
			get { return this.name; }
		}

		public PusherChannelType Type
		{
			get { return this.channelType; }
		}

		public PusherChannelState Status
		{
			get { return this.status; }
		}

		#endregion


		#region EventEmitter Methods

		public void Bind(string eventName, PusherDelegates.BindEventCallback callback)
		{
			if (this.status != PusherChannelState.Subscribed)
				return;
			this.eventEmitter.Bind(eventName, callback);
		}

		public void BindAll(PusherDelegates.BindEventCallback callback)
		{
			if (this.status != PusherChannelState.Subscribed)
				return;
			this.eventEmitter.BindAll(callback);
		}

		public void UnBind(string eventName, PusherDelegates.BindEventCallback callback)
		{
			if (this.status != PusherChannelState.Subscribed)
				return;
			this.eventEmitter.UnBind(eventName, callback);
		}

		public void UnBindAll(PusherDelegates.BindEventCallback callback)
		{
			if (this.status != PusherChannelState.Subscribed)
				return;
			this.eventEmitter.UnBindAll(callback);
		}

		internal void EmitEvent(string eventName, string data = null)
		{
			this.eventEmitter.EmitEvent(eventName, data);
		}

		#endregion


		#region Internal and Protected Methods

		internal virtual void Subscribe(PusherDelegates.ChannelStatusCallback callback = null)
		{
			this.statusCallback = callback;

			this.status = PusherChannelState.Subscribing;

			if (this.statusCallback != null)
			{
				this.statusCallback(this.status);
			}

			this.pusher.SendSubscribeRequest(this.name);
		}

		internal virtual void SubscriptionSucceeded(string data)
		{
			this.status = PusherChannelState.Subscribed;

			if (this.statusCallback != null)
			{
				this.statusCallback(this.status);
			}
		}

		internal virtual void SubscriptionFailed(string data)
		{
			this.status = PusherChannelState.Failed;

			if (this.statusCallback != null)
			{
				this.statusCallback(this.status);
			}
		}

		internal virtual void UnSubscribe()
		{
			this.status = PusherChannelState.UnSubscribing;

			if (this.statusCallback != null)
			{
				this.statusCallback(this.status);
			}

			this.pusher.SendUnSubscribeRequest(this.name);

			this.status = PusherChannelState.NotSubscribed;

			if (this.statusCallback != null)
			{
				this.statusCallback(this.status);
			}
		}

		#endregion


		#region Member Fields

		protected bool isDisposed;

		protected string name;
		protected PusherChannelType channelType;
		protected PusherChannelState status;
		protected PusherClient pusher;
		private PusherEventEmitter eventEmitter;

		protected PusherDelegates.ChannelStatusCallback statusCallback;

		#endregion
	}
}
